package com.dabai.qrtools.utils;


import android.os.Build;

import androidx.annotation.NonNull;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

/**
 * ShellUtils
 * 多用于root权限操作shell
 *
 * ShellUtils.CommandResult commandResult = ShellUtils.execCommand("echo hello", true, true);
 * if (commandResult.result == 0) {
 * DabaiUtils.showDialog(MainActivity.this, "成功！(successMsg=" + commandResult.successMsg + ")");
 * } else {
 * DabaiUtils.showDialog(MainActivity.this, "失败！(errorMsg=" + commandResult.errorMsg + ")");
 * }
 *
 */
public class ShellUtils {

    public static final String COMMAND_SU = "su";
    public static final String COMMAND_ZLSU = "zlsu";
    public static final String COMMAND_SH = "sh";
    public static final String COMMAND_EXIT = "exit\n";
    public static final String COMMAND_LINE_END = "\n";
    public static final String WRITEABLE = "rw";

    public static boolean remount(String io) {
        CommandResult commandResult = ShellUtils.execCommand("mount -o " + io + ",remount /system;\n", true);
        String manufacturer = Build.MANUFACTURER;
        if ("huawei".equalsIgnoreCase(manufacturer)) {
            ShellUtils.execCommand("mount -o ro,remount '/cust'", true);
        }
        if (commandResult.result != 0) {
            commandResult = ShellUtils.execCommand("mount -o ro,remount '/system_root'", true);

            if (commandResult.result != 0) {
                commandResult = ShellUtils.execCommand("mount -o rw,remount '/'", true);
            }
        }
        return commandResult.result == 0;
    }


    /**
     * 检查root权限
     *
     * @return boolean
     */
    public static boolean checkRootPermission() {
        return execCommand("echo root", true, false).result == 0;
    }


    /**
     * exec命令
     *
     * @param command 命令
     * @param isRoot  是否root
     * @return {@link CommandResult}
     */
    public static CommandResult execCommand(String command, boolean isRoot) {
        return execCommand(new String[]{command}, isRoot, true);
    }


    /**
     * exec命令
     *
     * @param commands 命令
     * @param isRoot   是否root
     * @return {@link CommandResult}
     */
    public static CommandResult execCommand(List<String> commands, boolean isRoot) {
        return execCommand(commands == null ? null : commands.toArray(new String[]{}), isRoot, true);
    }


    /**
     * exec命令
     *
     * @param commands 命令
     * @param isRoot   是否root
     * @return {@link CommandResult}
     */
    public static CommandResult execCommand(String[] commands, boolean isRoot) {
        return execCommand(commands, isRoot, true);
    }


    /**
     * exec命令
     *
     * @param command         命令
     * @param isRoot          是否root
     * @param isNeedResultMsg 是否需要结果信息
     * @return {@link CommandResult}
     */
    public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) {
        return execCommand(new String[]{command}, isRoot, isNeedResultMsg);
    }


    /**
     * exec命令
     *
     * @param commands        命令
     * @param isRoot          是否root
     * @param isNeedResultMsg 是否需要结果信息
     * @return {@link CommandResult}
     */
    public static CommandResult execCommand(List<String> commands, boolean isRoot, boolean isNeedResultMsg) {
        return execCommand(commands == null ? null : commands.toArray(new String[]{}), isRoot, isNeedResultMsg);
    }

    /**
     * exec命令
     *
     * @param commands        命令
     * @param isRoot          是否root
     * @param isNeedResultMsg 是否需要结果信息
     * @return {@link CommandResult}
     */
    public static CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) {
        int result = -1;
        if (commands == null || commands.length == 0) {
            return new CommandResult(result, null, null);
        }

        Process process = null;
        BufferedReader successResult = null;
        BufferedReader errorResult = null;
        StringBuilder successMsg = null;
        StringBuilder errorMsg = null;

        DataOutputStream os = null;
        try {
            process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
            os = new DataOutputStream(process.getOutputStream());
            for (String command : commands) {
                if (command == null) {
                    continue;
                }

                // donnot use os.writeBytes(commmand), avoid chinese charset error
                os.write(command.getBytes());
                os.writeBytes(COMMAND_LINE_END);
                os.flush();
            }
            os.writeBytes(COMMAND_EXIT);
            os.flush();

            result = process.waitFor();
            // get command result
            if (isNeedResultMsg) {
                successMsg = new StringBuilder();
                errorMsg = new StringBuilder();
                successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
                errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                String s;
                while ((s = successResult.readLine()) != null) {
                    successMsg.append(s);
                }
                while ((s = errorResult.readLine()) != null) {
                    errorMsg.append(s);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                if (successResult != null) {
                    successResult.close();
                }
                if (errorResult != null) {
                    errorResult.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (process != null) {
                process.destroy();
            }
        }
        return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null
                : errorMsg.toString());
    }


    /**
     * 命令的结果
     */
    public static class CommandResult {
        public static final int SUCCESS = 0;
        public static final int FAILED = 1;


        /**
         * 结果
         */
        public int result;

        /**
         * 成功信息
         */
        public String successMsg;

        /**
         * 错误信息
         */
        public String errorMsg;

        public CommandResult(int result) {
            this.result = result;
        }

        /**
         * 是成功的
         *
         * @return boolean
         */
        public boolean isSuccessful() {
            return result == 0;
        }

        /**
         * 命令的结果
         *
         * @param result     结果
         * @param successMsg 成功信息
         * @param errorMsg   错误信息
         */
        public CommandResult(int result, String successMsg, String errorMsg) {
            this.result = result;
            this.successMsg = successMsg;
            this.errorMsg = errorMsg;
        }

        @NonNull
        @Override
        public String toString() {
            return "CommandResult{" +
                    "result=" + result +
                    ", successMsg='" + successMsg + '\'' +
                    ", errorMsg='" + errorMsg + '\'' +
                    '}';
        }
    }


    /**
     * 授予许可
     * 用于给某个应用 授权
     *
     * @param packageName 包名
     * @param permission  许可
     * @return {@link CommandResult}
     */
    public static CommandResult grantPermission(String packageName, String permission) {
        String shellCommand = " pm grant " + packageName + " " + permission;
        return ShellUtils.execCommand(shellCommand, true);

    }


    /**
     * 撤销许可
     * 撤销权限
     *
     * @param packageName 包名
     * @param permission  许可
     * @return {@link CommandResult}
     */
    public static CommandResult revokePermission(String packageName, String permission) {
        String shellCommand = " pm revoke " + packageName + " " + permission;
        return ShellUtils.execCommand(shellCommand, true);

    }


    /**
     * 安装apk
     *
     * @param path 路径
     * @return {@link CommandResult}
     */
    public static CommandResult installApk(String path) {
        String shellCommand = " pm install -r " + path;
        return ShellUtils.execCommand(shellCommand, true);
    }

    /**
     * 卸载apk
     *
     * @param packageName 包名
     * @return {@link CommandResult}
     */
    public static CommandResult uninstallApk(String packageName) {
        String shellCommand = " pm uninstall " + packageName;
        return ShellUtils.execCommand(shellCommand, true);
    }

    /**
     * 启用应用程序
     *
     * @param packageName 包名
     * @return {@link CommandResult}
     */
    public static CommandResult enableApp(String packageName) {
        String shellCommand = " pm enable " + packageName;
        return ShellUtils.execCommand(shellCommand, true);
    }

    /**
     * 禁用应用程序
     *
     * @param packageName 包名
     * @return {@link CommandResult}
     */
    public static CommandResult disableApp(String packageName) {
        String shellCommand = " pm disable-user " + packageName;
        return ShellUtils.execCommand(shellCommand, true);
    }

    /**
     * 停用应用程序
     *
     * @param packageName 包名
     * @return {@link CommandResult}
     */
    public static CommandResult forceStopApp(String packageName) {
        String shellCommand = " am force-stop " + packageName;
        return ShellUtils.execCommand(shellCommand, true);
    }


}
